package flib;

import importExport.SVGLoader;
import importExport.XmlInOut;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Vector;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import peasy.PeasyCam;
import processing.core.PApplet;
import simpleGeom.Bounds3D;

import simpleGeom.HasPos2D;
import simpleGeom.HasPos3D;
import simpleGeom.Polygon2D;
import simpleGeom.Vec2D;
import simpleGeom.Vec3D;
import simpleGui.FileHelper;

public class FlibApplet extends PApplet {
	PeasyCam cam;

	int displayMode = 0;
	boolean single=true;
	Vector<Plan> plans;
	int iPlan=33;
	String folder;
	public void setup() {
		size(1600, 900, OPENGL);

		
		cam = new PeasyCam(this, 0, 0, 0, 5000);
		rectMode(CENTER);
		
		initData();
	}

	public void initData() {
		FloorplanLoader2D loader = new FloorplanLoader2D();
		loader.loadWallTypes(new File("../flibConfig.xml"));
		loader.loadRoomTypes(new File("../flibConfig.xml"));
		plans = new Vector<Plan>();
		Vector<File> files = FileHelper.getFilesFromFolder(folder,
				".svg");
		for (int j = 0; j < files.size(); j++) {
			File file = files.get(j);
			println(file.getAbsolutePath());
			Plan plan = loader.loadFloorplanSVG(file);
			plan.path=file.getAbsolutePath();
			plans.add(plan);
			
			// plan.findConvexCorners();
			 plan.triangulate();

			Vector<LevelAnalyser> levelAnalysers = new Vector<LevelAnalyser>();
			for (int i = 0; i < plan.levels.size(); i++) {
				LevelAnalyser lA = new LevelAnalyser();
				lA.parent = this;
				 lA.calculateDepth(plan.levels.get(i), 0.1f);
				//lA.calculateWall(plan.levels.get(i), 0.1f);
				levelAnalysers.add(lA);
			}
			plan.levelAnalysers = levelAnalysers;
		}
	}

	public void drawConvex(Plan plan) {
		stroke(255, 0, 255);
		for (int i = 0; i < plan.splitHEdges.size(); i++) {
			FlibHEdge hEdge = plan.splitHEdges.get(i);
			line(hEdge.x1(), hEdge.y1(), hEdge.z1(), hEdge.x2(), hEdge.y2(),
					hEdge.z2());
		}
		drawNodes(plan);
		drawWalls(plan);
	}

	public void drawGeometry(Plan plan) {
		fill(255, 0, 0);

		for (int i = 0; i < plan.walls.size(); i++) {
			FlibWall wall = plan.walls.get(i);
			FlibHEdge hE = wall.hEdge;
			if (wall.type != null) {
				stroke(wall.type.color.getRGB());
			}
			line(hE.x1(), hE.y1(), hE.z1() + 0.01f, hE.x2(), hE.y2(),
					hE.z2() + 0.01f);
			if (wall.type.label.equals("wall")) {
				noFill();
			} else {
				noFill();
			}
			beginShape(QUAD);
			vertex(hE.x1(), hE.y1(), hE.z1());
			vertex(hE.x2(), hE.y2(), hE.z2());
			vertex(hE.x2(), hE.y2(), hE.z2() + 2.99f);
			vertex(hE.x1(), hE.y1(), hE.z1() + 2.99f);
			endShape();
		}
		noStroke();
		for (int i = 0; i < plan.rooms.size(); i++) {
			FlibFace room = plan.rooms.get(i);
			fill(255);
			if (room.isPublic()){
				fill(200);
			}
			room.display3D(g);
		}
	}

	public void drawAnalyse(Plan plan) {
		System.out.println("analyse");
		fill(255);
		noStroke();
		// image(lA.analyse.get(),lA.sX,lA.sY,20,20);
		for (int i = 0; i < plan.levelAnalysers.size(); i++) {

			LevelAnalyser lA = plan.levelAnalysers.get(i);
			Bounds3D b = lA.b3d;
			beginShape(QUADS);
			texture(lA.analyse.get());
			vertex(b.getX1(), b.getY1(), b.z1, 0, 0);
			vertex(b.getX2(), b.getY1(), b.z1, b.getDimX() * 10f, 0);
			vertex(b.getX2(), b.getY2(), b.z1, b.getDimX() * 10f,
					b.getDimY() * 10f);
			vertex(b.getX1(), b.getY2(), b.z1, 0, b.getDimY() * 10f);
			endShape();
		}
		// rect(lA.sX,lA.sY,20,20);
		for (int i = 0; i < plan.walls.size(); i++) {
			FlibWall wall = plan.walls.get(i);
			FlibHEdge hE = wall.hEdge;
			if (wall.type != null) {
				stroke(wall.type.color.getRGB());
			}
			line(hE.x1(), hE.y1(), hE.z1() + 0.01f, hE.x2(), hE.y2(),
					hE.z2() + 0.01f);
			if (wall.type.label.equals("wall")) {
				noFill();
				fill(255);
			} else {
				noFill();
			}
			noStroke();
			stroke(100);
			Vec2D[] footprint = wall.calculateFootPrint();
			if (wall.type.label.equals("wall")
					|| wall.type.label.equals("window")) {
				fill(255);
				float h = 2.99f;
				if (wall.type.label.equals("window"))
					h = 1;
				for (int j = 0; j < footprint.length; j++) {
					HasPos2D n1 = footprint[j];
					HasPos2D n2 = footprint[(j + 1) % footprint.length];
					beginShape(QUAD);
					vertex(n1.getX(), n1.getY(), hE.z1());
					vertex(n2.getX(), n2.getY(), hE.z1());
					vertex(n2.getX(), n2.getY(), hE.z2() + h);
					vertex(n1.getX(), n1.getY(), hE.z2() + h);
					endShape();
				}
				beginShape();
				for (int j = 0; j < footprint.length; j++) {
					HasPos2D n1 = footprint[j];
					vertex(n1.getX(), n1.getY(), hE.z1() + h);
				}
				endShape(CLOSE);
			}
			/*
			 * beginShape(QUAD); vertex(hE.x1(), hE.y1(), hE.z1());
			 * vertex(hE.x2(), hE.y2(), hE.z2()); vertex(hE.x2(), hE.y2(),
			 * hE.z2() + 2.99f); vertex(hE.x1(), hE.y1(), hE.z1() + 2.99f);
			 * endShape();
			 */
		}

	}

	public void drawGeometrySolid(Plan plan) {
		fill(255, 0, 0);

		for (int i = 0; i < plan.walls.size(); i++) {
			FlibWall wall = plan.walls.get(i);
			FlibHEdge hE = wall.hEdge;
			if (wall.type != null) {
				stroke(wall.type.color.getRGB());
			}
			// line(hE.x1(), hE.y1(), hE.z1()+0.01f, hE.x2(), hE.y2(),
			// hE.z2()+0.01f);
			if (wall.type.label.equals("wall")) {
				noFill();
			} else {
				noFill();
			}
			Vec2D[] footprint = wall.calculateFootPrint();
			if (wall.type.label.equals("wall")) {
				for (int j = 0; j < footprint.length; j++) {
					HasPos2D n1 = footprint[j];
					HasPos2D n2 = footprint[(j + 1) % footprint.length];
					beginShape(QUAD);
					vertex(n1.getX(), n1.getY(), hE.z1());
					vertex(n2.getX(), n2.getY(), hE.z1());
					vertex(n2.getX(), n2.getY(), hE.z2() + 2.99f);
					vertex(n1.getX(), n1.getY(), hE.z2() + 2.99f);
					endShape();
				}
			}
			/*
			 * beginShape(QUAD); vertex(hE.x1(), hE.y1(),hE.z1());
			 * vertex(hE.x2(), hE.y2(),hE.z2()); vertex(hE.x2(),
			 * hE.y2(),hE.z2()+2.99f); vertex(hE.x1(), hE.y1(),hE.z1()+2.99f);
			 * endShape();
			 */
		}
		noStroke();
		for (int i = 0; i < plan.rooms.size(); i++) {
			FlibFace room = plan.rooms.get(i);
			fill(255);
			room.display3D(g);
		}
	}

	public void drawWalls(Plan plan) {
		for (int i = 0; i < plan.walls.size(); i++) {
			FlibWall wall = plan.walls.get(i);
			FlibHEdge hE = wall.hEdge;
			if (wall.type != null) {
				stroke(wall.type.color.getRGB());
			}
			line(hE.x1(), hE.y1(), hE.z1() + 0.01f, hE.x2(), hE.y2(),
					hE.z2() + 0.01f);

		}
	}

	public void drawTriangles(Plan plan) {
		fill(255, 0, 0);

		stroke(255, 0, 255);

		for (int i = 0; i < plan.triangulate.size(); i++) {
			FlibHEdge hEdge = plan.triangulate.get(i);
			line(hEdge.x1(), hEdge.y1(), hEdge.z1(), hEdge.x2(), hEdge.y2(),
					hEdge.z2());
			println("line");
		}
		for (int i = 0; i < plan.triangles.size(); i++) {
			HasPos2D[] tri = plan.triangles.get(i);
			fill(255f * i / plan.triangles.size(), 255, 255);
			beginShape(TRIANGLES);
			for (int j = 0; j < tri.length; j++) {
				HasPos3D p = (HasPos3D) tri[j];
				vertex(p.getX(), p.getY(), p.getZ());
			}
			endShape();
		}
		drawNodes(plan);
		drawWalls(plan);

	}

	public void drawGraph(Plan plan) {

		fill(255);
		rectMode(CENTER);
		noStroke();
		// pointLight(220,200,200,0,0,30);
		for (int i = 0; i < plan.rooms.size(); i++) {
			FlibFace room = plan.rooms.get(i);
			Vec3D gc = room.getGravityCenter();
			room.center = new FlibHENode(gc.x, gc.y, gc.z);
			fill(0, 255, 255);
			pushMatrix();
			translate(room.center.x, room.center.y, room.center.z);
			// rect(0,0,0.5f,0.5f);
			box(0.5f);
			popMatrix();

			// room.display3D(g);
		}

		for (int i = 0; i < plan.walls.size(); i++) {
			FlibWall wall = plan.walls.get(i);

			float cX = wall.cX();
			float cY = wall.cY();
			float cZ = wall.cZ();

			Room r1 = wall.getR1();
			Room r2 = wall.getR2();
			if (wall.type.permeable) {
				stroke(0, 255, 255);
				strokeWeight(4f);
				fill(0, 255, 255);
			} else if (wall.type.transparent) {
				strokeWeight(2f);
				stroke(0, 0, 255);
				fill(0, 0, 255);
			} else {
				strokeWeight(1f);
				stroke(255, 0, 0);
				fill(255, 0, 0);
			}
			if (r1 != null) {
				FlibHENode c1 = r1.center;
				line(cX, cY, cZ, c1.x, c1.y, c1.z);
			}
			if (r2 != null) {
				FlibHENode c1 = r2.center;
				line(cX, cY, cZ, c1.x, c1.y, c1.z);
			}
			noStroke();
			pushMatrix();
			translate(cX, cY, cZ);
			sphere(0.2f);
			// ellipse(0,0,0.5f,0.5f);
			popMatrix();
			pushMatrix();
			translate(wall.x1(), wall.y1(), wall.z1());
			sphere(0.1f);
			popMatrix();
			pushMatrix();
			translate(wall.x2(), wall.y2(), wall.z2());
			sphere(0.1f);
			popMatrix();

		}
		/*
		 * drawNodes(); drawWalls();
		 */
		noStroke();

	}

	public void drawNodes(Plan plan) {
		noStroke();
		for (int i = 0; i < plan.nodes.size(); i++) {
			FlibHENode n = plan.nodes.get(i);
			int nSize = n.getHEdges().size();
			if (nSize > 2) {
				fill(0, 255, 0);
			} else {
				fill(0, 255, 255);
			}
			pushMatrix();
			translate(n.x, n.y, n.z);
			box(0.25f);
			// rect(0,0,0.5f,0.5f);
			popMatrix();
		}
	}

	public void draw() {
		background(255);
		strokeWeight(2f);
		// pointLight(200, 200, 200, 20, 20, 20);
		lights();
		sphereDetail(3);
		scale(50);
		if (single){
			if (iPlan>=plans.size()){
				iPlan=0;
			}
			Plan plan=plans.get(iPlan);
			Bounds3D b3D=plan.getBounds3D();
			scale(2);
			pushMatrix();
			translate(-b3D.getCenterX(),-b3D.getCenterY(),0);
			drawPlan(plan);
			popMatrix();
		}
		if (!single){
	
		float dX=90;
		float x=-dX;
		float y=0;
		float maxY=0;
		translate(0,-40,0);
		for (int i = 0; i < plans.size(); i++) {
			Plan plan = plans.get(i);
			//println(plan.path);
			Bounds3D b3D=plan.getBounds3D();
			x+=(b3D.getDimX()*0.5f);
			if (x>dX){x=-dX+b3D.getDimX()*0.5f;
			y+=25;
		}
			pushMatrix();
			
			translate(x-b3D.getCenterX(),y-b3D.getCenterY(),0);
			noFill();
			drawPlan(plan);
			//rect(b3D.getCenterX(),b3D.getCenterY(),b3D.getDimX(),b3D.getDimY());
			popMatrix();
			
			
			
			x+=b3D.getDimX()*0.5f+1;
			
		}
		}
		// drawGeometry();

	}
	public void drawPlan(Plan plan){
		if (displayMode == 0) {
			drawGeometry(plan);
		}
		if (displayMode == 1) {
			// drawGeometrySolid();
		}
		if (displayMode == 1) {
			drawConvex(plan);
		}
		if (displayMode == 2) {
			drawTriangles(plan);
		}
		if (displayMode == 3) {
			drawGraph(plan);
		}
		if (displayMode == 4) {
			drawAnalyse(plan);
		}
	}

	public void keyPressed() {
		if (key=='d'){
		displayMode += 1;
		displayMode = displayMode % 5;
		}
		if (key=='s'){
			single=!single;
		}
		if (key=='i'){
			iPlan++;
		}
	}

}
